package com.andox.fn.inf.rpc.rest.proxy;

import java.lang.reflect.Proxy;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;

import com.andox.fn.inf.rpc.rest.config.ReferenceConfig;
import com.andox.fn.inf.rpc.rest.extension.ExtensionLoader;
import com.andox.fn.inf.rpc.rest.filter.Invoker;
import com.andox.fn.inf.rpc.rest.protocol.Protocol;
import com.andox.fn.inf.rpc.rest.protocol.ProtocolObjectFactory;
import com.andox.fn.inf.rpc.rest.util.ClassUtils;




/**   
 * @ClassName:   ReferenceFactoryBean   
 * @author:      Andox
 * @date:        2019年7月30日 下午5:51:09   
 *     
 */
public class ReferenceBean extends ReferenceConfig implements FactoryBean<Object>, InitializingBean{
	private static final long serialVersionUID = 8450431022846433526L;

	private ApplicationContext applicationContext;
	
	private AtomicBoolean inited = new AtomicBoolean(false);
	
	private Protocol protocol; 
	private Object proxy;
	
	public ReferenceBean(String interfaceClass) {
		this.setInterfaceClass(ClassUtils.forName(interfaceClass));
	}
	
	@Override
	public Object getObject() throws Exception {
		this.refer();
		
		return this.proxy;
	}

	private void refer() {
		if (StringUtils.isNoneBlank(this.getRegistry())) {
			protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(ProtocolObjectFactory.REGISTRY);
			Invoker invoker = protocol.refer(this);
			this.proxy = Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class<?>[] {this.getInterfaceClass()}, new InvokerInvocationHandler(invoker));
		}else {
			protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(this.getProtocol());
			Invoker invoker = protocol.refer(this);
			this.proxy = Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class<?>[] {this.getInterfaceClass()}, new InvokerInvocationHandler(invoker));
		}
	}
	
	@Override
	public Class<?> getObjectType() {
		return this.getInterfaceClass();
	}

	@Override
	public boolean isSingleton() {
		return true;
	}

	/**
	 * @return the applicationContext
	 */
	public ApplicationContext getApplicationContext() {
		return applicationContext;
	}

	/**
	 * @param applicationContext the applicationContext to set
	 */
	public void setApplicationContext(ApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
	}

	/**
	 * @return the inited
	 */
	public AtomicBoolean getInited() {
		return inited;
	}

	/**
	 * @param inited the inited to set
	 */
	public void setInited(AtomicBoolean inited) {
		this.inited = inited;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		this.checkSelf();
	}
}
